package com.loren.demo23.utils;

import com.loren.demo23.license.KeyPair;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;

import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

public class RSAUtils {

    public static KeyPair getKeyPair() throws IOException {
        RSAKeyPairGenerator rsaKeyPairGenerator = new RSAKeyPairGenerator();
        RSAKeyGenerationParameters rsaKeyGenerationParameters = new RSAKeyGenerationParameters(BigInteger.valueOf(3), new SecureRandom(), 1024, 25);
        rsaKeyPairGenerator.init(rsaKeyGenerationParameters);
        AsymmetricCipherKeyPair keyPair = rsaKeyPairGenerator.generateKeyPair();
        AsymmetricKeyParameter publicKey = keyPair.getPublic();
        AsymmetricKeyParameter privateKey = keyPair.getPrivate();
        SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKey);
        PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.createPrivateKeyInfo(privateKey);
        ASN1Object asn1ObjectPublic = subjectPublicKeyInfo.toASN1Primitive();
        byte[] publicInfoByte = asn1ObjectPublic.getEncoded();
        ASN1Object asn1ObjectPrivate = privateKeyInfo.toASN1Primitive();
        byte[] privateInfoByte = asn1ObjectPrivate.getEncoded();
        String publicKeyBase64 = Base64.getEncoder().encodeToString(publicInfoByte);
        String privateKeyBase64 = Base64.getEncoder().encodeToString(privateInfoByte);
        return new KeyPair(publicKeyBase64, privateKeyBase64);
    }

    public static String encrypt(String text, String keyPrivate) throws IOException, InvalidCipherTextException {
        AsymmetricBlockCipher blockCipher = new RSAEngine();
        byte[] privateInfoByte = Base64.getDecoder().decode(keyPrivate);
        AsymmetricKeyParameter keyParameter = PrivateKeyFactory.createKey(privateInfoByte);
        blockCipher.init(true, keyParameter);
        byte[] dataBytes = blockCipher.processBlock(text.getBytes(StandardCharsets.UTF_8), 0, text.getBytes(StandardCharsets.UTF_8).length);
        return Base64.getEncoder().encodeToString(dataBytes);
    }

    public static String decrypt(String text, String keyPublic) throws IOException, InvalidCipherTextException {
        byte[] dataBytes = Base64.getDecoder().decode(text);
        AsymmetricBlockCipher blockCipher = new RSAEngine();
        byte[] publicInfoByte = Base64.getDecoder().decode(keyPublic);
        AsymmetricKeyParameter keyParameter = PublicKeyFactory.createKey(publicInfoByte);
        blockCipher.init(false, keyParameter);
        return new String(blockCipher.processBlock(dataBytes, 0, dataBytes.length), StandardCharsets.UTF_8);
    }
}
